home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 1 / Meeting Pearls Vol 1 (1994).iso / installed_progs / text / faqs / solaris2.porting-faq < prev    next >
Encoding:
Internet Message Format  |  1994-04-26  |  46.0 KB

  1. Subject: Solaris 2 Porting FAQ
  2. Newsgroups: comp.unix.solaris,comp.answers,news.answers
  3. From: meyer@frostbite-falls.uoregon.edu (David M. Meyer 503/346-1747)
  4. Date: 25 Apr 1994 12:40:08 GMT
  5.  
  6.  
  7.  
  8. Archive-name:   Solaris2/porting-FAQ
  9. Last-modified:  Monday, April 25, 1994
  10. Version:        2.12
  11.  
  12. Solaris 2 Porting FAQ
  13. [Last changed: 25 April 1994]
  14.  
  15. This article contains the answers to some Frequently Asked
  16. Questions (FAQ) often seen in comp.unix.solaris that relate to
  17. porting BSD/Solaris 1 applications to Solaris 2. Over the first
  18. few days of its existence, it has evolved into a more general
  19. discussion about portability among Unix systems, especially as it
  20. relates to BSD, ANSI, POSIX, and SVID compliant systems.  It is
  21. hoped that this document will help reduce volume in this
  22. newsgroup and to provide hard-to-find information of general
  23. interest.
  24.         
  25.         Please redistribute this article!
  26.  
  27. This FAQ is maintained by David Meyer (meyer@ns.uoregon.edu).
  28. Send updates and corrections to me at this address.  It would
  29. help if the subject line contained the phrase "FAQ".
  30.  
  31. This article includes answers to the following questions.  Ones
  32. marked with a + indicate questions new to this issue; those with
  33. changes of content since the last issue are marked by *:
  34.  
  35. 0)  Which preprocessor symbols to use?
  36. 1)  Some Include File Issues
  37. 2)  Libraries
  38. 3)* Possible ANSI/POSIX/SVR4 replacements for some popular BSD functions 
  39. 4)  Signal Primer
  40. 5)  Waiting for Children to Exit
  41. 6)  Dealing with Shadow Password Files
  42. 7)  Some Compatabilty Problems
  43. 8)  Other Resources
  44.  
  45. -----------------------------------------------------------------------------
  46. 0) TOPIC: Which preprocessor symbols to use?
  47.  
  48. [Last modified: 11 October 93]
  49.  
  50. [Editor's Note: This section began life as a Solaris 1 and 
  51. Solaris 2 centric discussion. However, it has grown into a more 
  52. generalized portability discussion. I believe that this is a
  53. useful discussion, but it appears that contrasting styles,
  54. preferences, and requirements will make consensus difficult. DM]
  55.  
  56. Answer: This is a difficult and controversial question.
  57.  
  58. In order to understand the following discussion, we need to be
  59. aware of the following standards:
  60.  
  61. ANSI C (ANSI X3J11) 
  62.                 
  63.         This is the standard C definition, originally adopted as
  64.         American National Standard X3.159-1989 and has since been
  65.         adopted as international standard ISO/IEC 9899:1990.
  66.  
  67.                 
  68. POSIX.1 (IEEE 1003.1-1990)
  69.  
  70.         POSIX.1, the Portable Operating System Interface for
  71.         Computer Environments,  is a system level API that deals
  72.         with the function and format of system calls and
  73.         utilities such as signal handling. 
  74.  
  75. SVID3
  76.  
  77.         SVID3, the System V Interface Definition Issue 3, is is
  78.         fully compliant with POSIX.1, and is a arguably subset of
  79.         the SVR4 system API. For example, SVID3 doesn't have
  80.         "-ldl", but many people consider it of the SVR4 API. That
  81.         is, a system could be SVID3-compliant without necessarily
  82.         being an SVR4 system.
  83.  
  84. XPG
  85.  
  86.         XPG, X/Open Company Ltd's X/Open Portability Guide, is a
  87.         broad document which covers a great number of areas,
  88.         including operating systems and programming languages,
  89.         system interfaces, and internetworking. The latest
  90.         version, XPG4, groups these components into "profiles",
  91.         which are packaged together according to market needs.
  92.  
  93.  
  94. Two additional standards are relevant for Suns:
  95.  
  96. SCD 2.0 and x86 ABIs
  97.  
  98.         SCD 2.0 is the SPARC Compliance Definition 2.0. The SCD
  99.         has two components: On the hardware side, 
  100.  
  101.          (i).   System Compliance Test verifies that the hardware
  102.                 and operating system successfully emulates what
  103.                 Sun is doing. It covers low level system issues
  104.                 such as alignment, and linking and loading. 
  105.  
  106.         (ii).   The SPARC Application Verifier tests software to
  107.                 be sure that it runs on SCD hardware. 
  108.  
  109.                 
  110. As an example of subtle differences that exist between the BSD
  111. interface and SVID/POSIX standards, consider the BSD mktemp(3)
  112. call. The SunOS 4.1 mktemp() replaced the trailing X characters
  113. with the letter (e.g., X) and the current process ID. The SVID
  114. and SVR4 versions specify only that the six trailing Xs be
  115. replaced with a character string that can be used to create a
  116. unique filename, and does not depend on the specific name of the
  117. file.  Thus, the BSD and SVR4/SVID3 versions are only
  118. semantically equivalent in the case where only the application
  119. cares that the filename is unique.
  120.  
  121. Now, the basic philosophical question of which preprocessor
  122. contstucts to use here would appear to revolve around the
  123. following choices: 
  124.  
  125.         (i).    Use a high level, large grained standard
  126.                 definition (e.g., _POSIX_SOURCE). In this case,
  127.                 features are implicitly defined. One problem with
  128.                 such definitions is that they may cause other
  129.                 useful functions to become unavailable. However,
  130.                 there are several such definitions in common use.
  131.                 For operating systems, we have
  132.  
  133.                         SVR4
  134.                         SYSV
  135.                         BSD
  136.                         OSF1
  137.  
  138.                 to name a few. For standards, we are mainly
  139.                 interested interested symbols such as 
  140.  
  141.                         __STDC__
  142.                         _POSIX_SOURCE
  143.                         _XOPEN_SOURCE
  144.                 
  145.   
  146.                 This method is not without pitfalls.  For
  147.                 example, the Sun SC2.0.1 compiler defines
  148.                 __STDC__ as 0 when compiling in transition mode
  149.                 (-Xt), only setting it to 1 when the strict ANSI 
  150.                 mode (-Xc) is used. The expression 
  151.  
  152.                         #if (__STDC__ - 0 == 0) 
  153.  
  154.                 can be used to recognize strict v. transition
  155.                 ANSI modes. On Solaris 2, if you compile with
  156.                 -Xc, you will lose all non-ANSI functionality.
  157.                 However, you can define _POSIX_SOURCE or
  158.                 _XOPEN_SOURCE to get a POSIX or XOPEN
  159.                 environment.   
  160.                 
  161.                 If you use _POSIX_SOURCE, .eg., 
  162.                 
  163.                         #define _POSIX_SOURCE 1
  164.  
  165.                 then all symbols not defined by Standard C or the
  166.                 POSIX standard will be hidden (except those with
  167.                 leading underscores). If you wish to use
  168.                 _POSIX_SOURCE, be sure to define it before
  169.                 including any standard header files, and avoid
  170.                 name clashes by not defining any symbols that
  171.                 begin with "_" (Similarly, note that almost all
  172.                 names beginning with  "E" are reserved by
  173.                 errno.h, and many names prefixed by "va_"
  174.                 reserved by stadarg.h). 
  175.  
  176.                 One more note on _POSIX_SOURCE:   SunOS 5.3 has
  177.                 introduced the new header file <sys/feature_tests.h>. 
  178.                 This file is included in all files which have
  179.                 _POSIX_SOURCE dependancies. 
  180.  
  181.                 A new symbol,  _POSIX_C_SOURCE was introduced in POSIX.2
  182.                 (V1 P720, L51) as a mechanism to enable POSIX.1 and
  183.                 POSIX.2 symbols. Its values are as follows:
  184.  
  185.                 /*
  186.                  *      Values of _POSIX_C_SOURCE
  187.                  *
  188.                  *              undefined       not a POSIX compilation
  189.                  *                      1       POSIX.1-1990 compilation
  190.                  *                      2       POSIX.2-1992 compilation
  191.                  *                1993xxL       POSIX.4-1993 compilation
  192.                  */
  193.  
  194.  
  195.                 This means that POSIX.2 says that a value of 1 = POSIX.1
  196.                 and a value of 2 = POSIX.1 & POSIX.2. The idea here is
  197.                 to provide a single control point over the POSIX namespace,
  198.                 rather than having to edit each file individually. 
  199.  
  200.                 Another potential portability pitfall is the
  201.                 __svr4__ feature defined by the FSF (gcc). If you
  202.                 depend on __svr4__, you may lose portability.
  203.                 gcc also defines sun if you don't give the -ansi
  204.                 argument. If you use -ansi,  then sun is not
  205.                 defined and __sun__ is.
  206.  
  207.                 Finally, complexity may arise surrounding a
  208.                 feature which may be part of some vendor's
  209.                 version of some system Y, but may also exist in
  210.                 non-Y compliant systems. Consider, for example,
  211.                 shadow passwording. Systems conforming to the
  212.                 latest SVID (e.g., SVR4) have shadow.h, but there
  213.                 are many systems that have shadow.h without
  214.                 conforming to the SVID.
  215.  
  216.                 So, in general, for code that uses a STD_FEATURE and
  217.                 runs on systems W, Y, and Z, you are left with 
  218.                 something that may look like   
  219.  
  220.                         #if defined(W)                          ||
  221.                            (defined(Y) && _Y_VERSION_ > 3)      ||
  222.                            (defined(Z) || defined(__Z__))
  223.                         #include <STD_FEATURE.h>
  224.                         #endif
  225.  
  226.                 [W, Y, Z are things like SVR4, AIX, NeXT, BSD,
  227.                 and so on. STD_FEATURE.h is something like shadow.h] 
  228.  
  229.                 This example exposes two problems the large
  230.                 grained method. First, it forces one to keep
  231.                 track of exactly which vendors supply
  232.                 <STD_FEATURE.h>.  Second, the complexity of the
  233.                 preprocessor expressions may be a serious
  234.                 consideration, since their complexity is
  235.                 something like     
  236.  
  237.                         O(n*m) where
  238.  
  239.                         n = the number of standard features, and
  240.                         m = number of vendors/systems
  241.  
  242.  
  243.         (ii).   Define new fine-grained feature tests (e.g.,
  244.                 HAVE_POSIX_SIGNALS, or HAVE_SHADOW_H) for
  245.                 features of interest. Such fine-grained features
  246.                 could be used in conjunction with large grained
  247.                 definitions. An nice example of using feature
  248.                 definitions is the GNU configure program. It
  249.                 uses, for example, the features HAVE_BCOPY and
  250.                 HAVE_MEMSET to enable either the bcopy (BSD) or
  251.                 memset (ANSI) functions.   
  252.  
  253.                 Feature testing has the advantage of being useful
  254.                 for automatic configuration with programs such as
  255.                 GNU configure. GNU configure outputs statements
  256.                 of the form
  257.                 
  258.  
  259.                         #define HAVE_aaaa
  260.                         #define HAVE_bbbb
  261.                         #define HAVE_cccc
  262.                         ....
  263.  
  264.                 Another way to generate a feature set is by
  265.                 using the symbol defining the system, e.g., 
  266.  
  267.                         #ifdef SVR4
  268.                         #define HAVE_aaaa
  269.                         #define HAVE_bbbb
  270.                         #define HAVE_cccc
  271.                         ....
  272.  
  273.                         #endif
  274.                         #ifdef BSD43
  275.                         #define HAVE_yyyy
  276.                         ...
  277.                         #endif
  278.                         #ifdef NEWTHING
  279.                         #define HAVE_zzzz
  280.                         ...
  281.                         #endif
  282.         
  283.                 Feature testing also helps to avoid constructs
  284.                 such as 
  285.  
  286.                 #if defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)
  287.  
  288.                 [Editor's Note: Finally, an observation: The real
  289.                 issue here appears to be how many of these
  290.                 "features" are migrating to the standard
  291.                 operating systems and interfaces, and how many
  292.                 vendors are implementing these standards. In
  293.                 general, some people feel that feature testing
  294.                 improves portability (and readability), and
  295.                 others believe that the feature testing style 
  296.                 decreases portability and readability. DM]  
  297.  
  298.  
  299.         (iii).  Use some part of the feature's definition itself
  300.                 to enable the feature, for example 
  301.  
  302.                         #ifdef _IOLBF
  303.                                 setvbuf(stderr, NULL, _IOLBF, 0);
  304.                         #else
  305.                                 setlinebuf(stderr);
  306.                         #endif  /* _IOLBF  */
  307.  
  308.                 Note that in this case, another, possibly better
  309.                 option is (consider the case in which some vendor
  310.                 has inadvertently defined _IOLBF for some other
  311.                 purpose):
  312.  
  313.                         #ifdef   __STDC__
  314.                                 setvbuf(stderr, NULL, _IOLBF, 0);
  315.                         #else
  316.                                 setlinebuf(stderr);
  317.                         #endif  /* __STDC__  */
  318.  
  319.                 since setvbuf is required by Standard C.
  320.  
  321.  
  322.  
  323.         Finally, some people have suggested the use of
  324.         expressions like 
  325.  
  326.                 #if defined(sun) && defined(__svr4__)
  327.                         <Solaris 2 centric code>
  328.                 #else 
  329.                         ...
  330.                 #endif
  331.  
  332.  
  333.         As noted above, the __svr4__ feature is defined by the
  334.         FSF (gcc). If you depend on __svr4__, you may lose 
  335.         portability. gcc also defines sun if you don't give the
  336.         -ansi argument. If you use -ansi,  then sun is not
  337.         defined and __sun__ is. The implication here is that
  338.         depending on symbols defined by a given compiler can
  339.         reduce portability.
  340.  
  341.         In general, such a construct should be used if and only if
  342.         the code in question cannot be covered by some standard
  343.         (e.g., SVR4, _POSIX_SOURCE, etc.). Note that it is also
  344.         compiler specific.
  345.         
  346.  
  347. -----------------------------------------------------------------------------
  348. 1) TOPIC: Include File Issues
  349.  
  350. [Last modified: 19 August 93]
  351.  
  352. The first and apparently most common problem is that
  353. /usr/include/strings.h is not ANSI compliant, and as such does not
  354. exist on Solaris 2 (or SVR4). It should be replaced by
  355. /usr/include/string.h, e.g. (following GNU feature definition
  356. conventions)
  357.  
  358.         #if HAVE_STRING_H || defined(STDC_HEADERS)
  359.         #include <string.h>
  360.         #else
  361.         #include <strings.h>
  362.         #endif
  363.         #if defined(STDC_HEADERS)
  364.         #include <stdlib.h>
  365.         #endif /* HAVE_STRING_H */
  366.  
  367.         while ANSI-C requires the name be string.h, one might
  368.         define this as
  369.  
  370.         #ifdef __STDC__
  371.         #include <string.h>
  372.         #else
  373.         #include <strings.h>
  374.         #endif  /* __STDC__ */
  375.  
  376.         However, this again neglects the case in which the vendor 
  377.         provides string.h in a non-ANSI environment.
  378.  
  379.                         
  380. Another thing to watch is for the symbols O_CREAT, O_TRUNC, and
  381. O_EXCL being undefined. On BSD systems, these are defined in
  382. <sys/file.h>. On Solaris 1 systems (beginning with SunOS 4.0) ,
  383. these are defined in <sys/fnctlcom.h> (which is included in
  384. <sys/file.h>). On a POSIX compliant system, these symbols are
  385. defined in <fcntl.h>, which is not included in <sys/file.h>.
  386. Since <fcntl.h> is defined on SunOS 4.1.x, replacing <sys/file.h>
  387. with <fcntl.h> works for both SunOS 4.1.x and SVR4. See, for
  388. example, section 5.3.1.1 of the POSIX spec.
  389.  
  390.  
  391. -----------------------------------------------------------------------------
  392.  
  393. 2) TOPIC: Libraries
  394.  
  395. [Last modified: 12 Feburary 94]
  396.  
  397. Network Libraries:
  398.  
  399. Many of the network functions and definitions that were present
  400. in the BSD libc are now in libnsl.so and libsocket.so. Thus
  401. networking code will generally need to be linked with -lsocket
  402. -lnsl. Since libsocket.so requires libnsl.so (it is NEEDED), you must
  403. specify them in this order. Note that you need libnsl.so for functions
  404. like gethostbyname (see gethostbyname note below). Incidently, you can
  405. look at selected parts of an object file using dump(1), e.g.,  
  406.  
  407.         % dump -Lv /usr/lib/libsocket.so
  408.  
  409.         /usr/lib/libsocket.so:
  410.  
  411.           **** DYNAMIC SECTION INFORMATION ****
  412.         .dynamic :
  413.         [INDEX] Tag      Value
  414.         [1]     NEEDED   libnsl.so.1
  415.         [2]     INIT     0x3174
  416.  
  417.         [...]
  418.         
  419. Regular Expressions
  420.  
  421. Another problem frequently encountered is that the regexp
  422. functions (see regexpr(3G)) are not defined in libc. On Solaris
  423. 2, you must link with libgen.a (-lgen) in order to get these
  424. definitions. See Intro(3) for a more complete discussion.
  425.  
  426. Name List (nlist)
  427.  
  428. You must link with libelf.a (-lelf) to get the nlist(3E)
  429. definition. 
  430.  
  431. -----------------------------------------------------------------------------
  432.  
  433. 3)* TOPIC: Possible ANSI/POSIX/SVR4 replacements for some popular
  434.            BSD functions  
  435.  
  436. [Last modified: 28 Feburary 94]
  437.  
  438. [Editor's Note: Once again, this section began life a SunOS 4.1.x 
  439. and SunOS 5.x centric discussion.  It too has grown into a
  440. discussion dealing with general portability for BSD to other
  441. standards. DM]
  442.  
  443. Problems finding functions that were defined in the BSD libc.a is
  444. one of the most frequently asked porting questions. The following
  445. table and code fragments suggest substitutes for some common BSD
  446. constructs (more complete lists can be found in some of the texts
  447. listed in section 7 below).
  448.  
  449.  
  450. BSD                     Possibilities           Standards/Notes
  451. ============================================================================
  452. srandom(seed)           srand(seed)             ANSI-C (Also, some older UNIX)
  453.                         srand48(seed)           SVR4
  454.  
  455. non-ANSI signal()       sigset()                SVR4   (systems calls not
  456. (e.g., SunOS)                                          restarted, but bytes r/w
  457.                                                        returned, else EINTR) 
  458.                         sigaction               POSIX  (but extensible by
  459.                                                        implementation) 
  460.  
  461. sigvec                  sigaction               POSIX
  462. sigblock                sigprocmask             POSIX
  463.                         sigset(.., SIG_HOLD)
  464.                         sighold                 SVR4
  465. sigsetmask              sigprocmask             POSIX
  466.                         sigset/sigrelse         SVR4    
  467.  
  468. sigpause                sigsuspend              POSIX
  469.         
  470. setjmp                  sigsetjmp               POSIX 
  471. longjmp                 siglongjmp              POSIX 
  472.  
  473. statfs                  statvfs                 SVR4
  474.  
  475. bcopy                   memmove                 ANSI-C (BSD bcopy() handles
  476.                                                        overlapping areas
  477.                                                        correctly, as does
  478.                                                        memmove, but not memcpy)
  479.  
  480. bzero                   memset                  ANSI-C
  481.  
  482. index                   strchr                  ANSI-C
  483. rindex                  strrchr                 ANSI-C
  484.  
  485. getwd                   getcwd                  POSIX
  486.  
  487. getrusage               open,ioctl              The getrusage information
  488.                                                 (and a whole lot more) can be
  489.                                                 found in the prusage structure.
  490.                                                 Use the PIOCUSAGE ioctl. See
  491.                                                 the example below and the
  492.                                                 proc(4) man page for detail. 
  493.  
  494.  
  495. gethostname             sysinfo(SI_HOSTNAME,..) SVR4   See sysinfo(2) for
  496.                                                        many other possible
  497.                                                        values
  498.  
  499. getdtablesize           sysconf(_SC_OPEN_MAX)   POSIX  See sysconf(3C) for
  500.                                                        many other values
  501.                                                        available via sysconf.
  502.  
  503.  
  504. timelocal               mktime                          
  505.  
  506. wait3 w/o rusage        waitpid                 POSIX
  507. wait3                   waitid                  SVR4
  508.  
  509. usleep                   nanosleep              POSIX See nanosleep(3R) on
  510.                                                 Solaris 2.3 (see libposix4.a) 
  511.                                                 For a Solaris 2.[0-2], see the
  512.                                                 example below.
  513.  
  514.  
  515. ------------------------------------------------------------------
  516.  
  517.         Timing Problems
  518.         ---------------
  519.  
  520.         POSIX defines the <sys/times.h> function for subsecond
  521.         timing.  Sun seems to provide about 1/60 second accuracy. 
  522.  
  523.         #include <stdio.h>
  524.         #include <sys/times.h>   /* for struct tms and times() */
  525.         #include <time.h>        /* for CLK_TCK value */
  526.  
  527.         int main(void) {
  528.            struct tms tms_start, tms_finish;  /* user and system time */
  529.            clock_t start, finish;             /* real time */
  530.            start = times( &tms_start );
  531.            /* ... do something ... */
  532.            finish = times( &tms_finish );
  533.            printf("(in seconds) %f real, %f system, %f user\n",
  534.                (finish-start) / (double)CLK_TCK,
  535.                (tms_finish.tms_stime-tms_start.tms_stime) / (double)CLK_TCK,
  536.                (tms_finish.tms_utime-tms_start.tms_utime) / (double)CLK_TCK);
  537.            return 0;
  538.         }
  539.  
  540.         You might want to divide CLK_TCK by 1000.0 to get more
  541.         precise millisecond values.  times() returns -1 if it
  542.         cannot provide timing information.
  543.  
  544.         While Solaris 2 conforms to POSIX, SunOS 4.1 defines
  545.         times() as returning a flag instead of elapsed real time.
  546.         You can use ftime() to get elapsed real time:
  547.  
  548.         #include <stdio.h>
  549.         #include <sys/types.h>  /* for time_t */
  550.         #include <sys/timeb.h>  /* for ftime() and struct timeb */
  551.  
  552.         int main(void) {
  553.            struct timeb start, finish;
  554.            double real_secs;
  555.            ftime( &start );
  556.            /* ... do something ... */
  557.            ftime( &finish );
  558.            real_secs = finish.time - start.time;
  559.            if ( finish.millitm < start.millitm )
  560.               real_secs = (real_secs-1) +
  561.                           (1000+start.millitm-finish.millitm)/1000.0;
  562.            else
  563.               real_secs = (finish.millitm-start.millitm)/1000.0;
  564.            printf( "That took %f real seconds.", real_secs );
  565.            return 0;
  566.         }
  567.  
  568.         The ANSI C function clock() can also be used for timing.
  569.         It returns elased "processor" time, which is equivalent
  570.         to system+user time. While it also returns a clock_t
  571.         value, you must divide the difference between to calls to
  572.         clock() by CLOCKS_PER_SEC, *not* CLK_TCK.  The values are
  573.         different by orders of magnitude.  SunOS 4.1 doesn't seem
  574.         to provide CLOCKS_PER_SEC or CLK_TCK in <time.h>.  Try
  575.         10000000 and 60, respectively.
  576.  
  577.  
  578.  
  579.         Compatibility Functions
  580.         -----------------------
  581.  
  582.         /*
  583.          *      getrusage --
  584.          */
  585.  
  586.         #include <sys/resource.h>
  587.         #ifndef RUSAGE_SELF
  588.         #include <sys/procfs.h>
  589.         #endif
  590.  
  591.         #ifdef PIOCUSAGE
  592.                 int             fd;
  593.                 char            proc[SOMETHING];
  594.                 prusage_t       prusage;
  595.  
  596.                 sprintf(proc,"/proc/%d", getpid());
  597.                 if ((fd = open(proc,O_RDONLY)) == -1) {
  598.                         perror("open");
  599.                         ....
  600.                 }
  601.                 if (ioctl(fd, PIOCUSAGE,, &prusage) == -1) {
  602.                         perror("ioctl");
  603.                         ...
  604.                 }
  605.                 ....
  606.         #else                   /* Again, assume BSD */
  607.                 if (getrusage(RUSAGE_SELF, &rusage) == -1) {
  608.                         perror("getrusage");
  609.                         ....
  610.                 }
  611.                 ....
  612.         #endif /* PIOCUSAGE */
  613.  
  614.  
  615.  
  616.         /*
  617.          *      setlinebuf --
  618.          *
  619.          */
  620.         
  621.         #ifdef   __STDC__
  622.                 setvbuf(stderr, NULL, _IOLBF, 0);
  623.         #else
  624.                 setlinebuf(stderr);
  625.         #endif  /* __STDC__  */
  626.  
  627.  
  628.         /*
  629.          *      gethostid 
  630.          *
  631.          *      This example has a combination of high-level
  632.          *      (SVR4) and (SI_HW_SERIAL) feature declarations.
  633.          */
  634.         
  635.         #if defined(SVR4) && defined(SI_HW_SERIAL)
  636.         long  gethostid() {
  637.                         
  638.           char buf[128];
  639.                 
  640.           if (sysinfo(SI_HW_SERIAL, buf, 128) == -1) {
  641.             perror("sysinfo");
  642.             exit(1);
  643.           }
  644.           return(strtoul(buf,NULL,0));
  645.         }
  646.         #endif /* SVR4 && SI_HW_SERIAL */
  647.  
  648.  
  649.         /*
  650.          *      getdtablesize --
  651.          *
  652.          *      Several possibilites here. Note that while one
  653.          *      can emulate getdtablesize with getrlimit on SVR4
  654.          *      or 4.3BSD (or later), these systems should be
  655.          *      POSIX.1 compliant, so sysconf is preferred.
  656.          *
  657.          */
  658.  
  659.         #ifdef  _SC_OPEN_MAX            /* POSIX -- preferred */
  660.                 if ((tableSize = sysconf(_SC_OPEN_MAX)) == -1) {
  661.                         perror("sysconf");
  662.                         ...
  663.                 }
  664.         #elif   RLIMIT_NOFILE           /* who is non POSIX but has this? */
  665.                 if (getrlimit(RLIMIT_NOFILE, &rlimit) == -1) {
  666.                         perror("getrlimit");
  667.                         exit(1);
  668.                 }
  669.                 tableSize = rlimit.rlim_max;
  670.         #else                           /* assume old BSD type */
  671.                 tableSize = getdtablesize();
  672.         #endif
  673.  
  674.  
  675. ------------------   
  676.  
  677.         /*
  678.          * gethostname  --
  679.          *
  680.          */
  681.  
  682.         #ifdef  SVR4 
  683.         #include <sys/systeminfo.h>
  684.         #endif  /* SVR4 */ 
  685.  
  686.                 ....
  687.  
  688.                 char buf[MAXHOSTNAME]
  689.  
  690.         #ifdef  SVR4
  691.                 if (sysinfo(SI_HOSTNAME, buf, sizeof(buf)) <0) {
  692.                         perror("SI_HOSTNAME");
  693.                         exit(BAD);
  694.                 }
  695.         #else   /* Assume BSD */
  696.                 if (gethostname(buf, sizeof(buf)) < 0) {
  697.                         perror("gethostname");
  698.                         exit(BAD);
  699.                 }
  700.         #endif  /* SVR4 */
  701.  
  702.         /* buf has hostname here... */
  703.  
  704.  
  705.         /*
  706.          *      usleep(delay)  --
  707.          *
  708.          *      Possible usleep replacement. Delay in microseconds.
  709.          *      Another possiblity is to use poll(2). On Solaris
  710.          *      2.x, select is just a wrapper for poll, so you
  711.          *      are better off using it directly.  If you use,
  712.          *      poll, note that it uses millisecond resolution,
  713.          *      and is not affected by the O_NDELAY and O_NONBLOCK 
  714.          *      flags.
  715.          *
  716.          *      Note that using nanosleep has portability implications,
  717.          *      even across different versions of Solaris 2.x. In
  718.          *      particular, only Solaris 2.3 has libposix4, and 
  719.          *      hence nanosleep. Select (or poll) is a better option if 
  720.          *      you need portability across those versions.
  721.          *
  722.          *      If you define USE_NANOSLEEP, be sure to link with -lposix4
  723.          *
  724.          */
  725.  
  726.         #include <unistd.h>
  727.         #include <stdlib.h>
  728.         #include <stdio.h>
  729.         #include <errno.h>
  730.         #include <time.h>
  731.         #include <sys/time.h>
  732.         #include <sys/param.h>
  733.         #include <sys/types.h>
  734.         #ifdef  USE_POLL
  735.         #include <stropts.h>
  736.         #include <poll.h>
  737.         #endif  /* USE_POLL */
  738.         
  739.         int     usleep(unsigned long int useconds)
  740.         {
  741.         #ifdef  USE_NANOSLEEP
  742.           struct timespec rqtp;
  743.         
  744.           rqtp.tv_sec  = useconds / (unsigned long)  1000000;
  745.           rqtp.tv_nsec = (useconds % (unsigned long) 1000000) * 1000 ;
  746.         
  747.           if (nanosleep(&rqtp,  (struct  timespec *) NULL) == -1)
  748.             perror("nanosleep");
  749.           return (0);
  750.         
  751.         #elif   USE_POOL
  752.           struct pollfd unused;
  753.         
  754.           if (poll(&unused,0,(useconds/1000)) == -1) 
  755.             perror("poll");
  756.           return(0);
  757.         #elif   USE_USLEEP
  758.           struct timeval delay;
  759.         
  760.           delay.tv_sec = 0;
  761.           delay.tv_usec = useconds;
  762.           if (select(0,
  763.                      (fd_set *) NULL,
  764.                      (fd_set *) NULL,
  765.                      (fd_set *) NULL,
  766.                      &delay) == -1)
  767.             perror("select");
  768.           return (0);
  769.         #endif                  /* USE_NANOSLEEP */
  770.         
  771.         
  772.         /*
  773.          *      tzsetwall -- 
  774.          */
  775.         
  776.         void tzsetwall()
  777.         {
  778.           unsetenv("TZ");
  779.           tzset();
  780.         }
  781.  
  782.         /*
  783.          *      gethostybname --
  784.          *
  785.          *      The following code was contributed by Casper H.S. Dik
  786.          *      to address the following problem:
  787.          *
  788.          *      gethostbyname() always returns null in h->aliases.
  789.          *      Now, gethostbyX can be replaced its __switch_gethostbyX
  790.          *      equivalents. However, these are missing from Solaris 2.3.
  791.          *
  792.          *      The _r functions are reentrant.  They have a different
  793.          *      calling sequence. (The __switch_getXXXbyYYY are called
  794.          *      like getXXXbyYYY, the _switch_getXXXbyYYY_r are called
  795.          *      like getXXXbyYYY_r) 
  796.          *
  797.          *      With this bit of knowledge I constructed the code that
  798.          *      follows this message. Just plug it in every program
  799.          *      that requires gethostbyname to work. (Gethostbyaddr()
  800.          *      is added for symmetry). 
  801.          *
  802.          *      You'll need to link with -lnsl -ldl.
  803.          *
  804.          *      It works for Solaris 2.2 and 2.3.  (Compiled on 2.3 or
  805.          *      2.2 it will run 2.2 and 2.3)
  806.          *
  807.          *      Note that as with __switch* _switch*_r is undocumented
  808.          *      and can be changed in the next release.
  809.          *
  810.          */
  811.         
  812.         /*
  813.          *     Proper gethostbyXX function for Solaris 2.0-2.3
  814.          *     (and later ?) 
  815.          *
  816.          *     Fixed in 2.4?
  817.          *
  818.          *     You'll need -ldl added to the link command line.
  819.          *
  820.          *     Casper Dik (casper@fwi.uva.nl)
  821.          *
  822.          */
  823.  
  824.         #include <netdb.h>
  825.         #include <dlfcn.h>
  826.         
  827.         #define HBUFSIZE 4096
  828.         
  829.         static void *dlhandle;
  830.         /* The gethostbyXXX function variables. Named after
  831.         * then .so files they appear in. nsw*.so in SunOS 5.2
  832.         * and earlier, nss_*.so in 5.3 */ 
  833.         static struct hostent *(*nswghba)(const char *, int, int),
  834.                               *(*nswghbn)(const char *),
  835.                               *(*nss_ghba)(const char *,
  836.                                            int, int,
  837.                                            struct hostent *, char *, int, int *),
  838.                               *(*nss_ghbn)(const char *,
  839.                                            struct hostent *, char *, int, int *);
  840.         
  841.         static int dlinit(void)
  842.         {
  843.           static int dlstatus = 0; /* 0 = uninited, 1 = inited & ok, -1 = error */
  844.         
  845.           if (dlstatus)
  846.             return dlstatus;
  847.         
  848.           dlstatus = -1;
  849.         
  850.           dlhandle = dlopen(0, RTLD_LAZY);
  851.         
  852.           if (dlhandle == 0)
  853.             return dlstatus;
  854.         
  855.           /* SunOS 5.0 - 5.2 */
  856.           nswghba = (struct hostent *(*)(const char *, int, int))
  857.             dlsym(dlhandle, "__switch_gethostbyaddr");
  858.         
  859.           nswghbn = (struct hostent *(*)(const char *))
  860.             dlsym(dlhandle, "__switch_gethostbyname");
  861.         
  862.           /* either both should exist or both should not exist */
  863.           if ((nswghbn == 0) != (nswghba == 0))
  864.             return dlstatus;
  865.         
  866.           if (nswghbn)
  867.             return dlstatus = 1;
  868.         
  869.           /* SunOS 5.3 - ? */
  870.           nss_ghba = (struct hostent *(*)
  871.                       (const char *, int, int, struct hostent *, char *, int , int *))
  872.             dlsym(dlhandle, "_switch_gethostbyaddr_r");
  873.         
  874.           nss_ghbn = (struct hostent *(*)
  875.                       (const char *, struct hostent *, char *, int , int *))
  876.             dlsym(dlhandle, "_switch_gethostbyname_r");
  877.         
  878.           /* these two must exist when we get here */
  879.           if (nss_ghbn != 0 && nss_ghba != 0)
  880.             dlstatus = 1;
  881.         
  882.           return dlstatus;
  883.         }
  884.         
  885.         struct hostent *
  886.         gethostbyname(const char *name) {
  887.         
  888.           static struct hostent hp;
  889.           static char buf[HBUFSIZE];
  890.         
  891.           if (dlinit() == -1)
  892.             return 0;
  893.         
  894.           if (nswghbn)
  895.             return nswghbn(name);
  896.           else
  897.             return nss_ghbn(name, &hp, buf, sizeof(buf), &h_errno);
  898.         }
  899.         
  900.         struct hostent *
  901.         gethostbyaddr(const char *addr, int len, int type) {
  902.           static struct hostent hp;
  903.           static char buf[HBUFSIZE];
  904.         
  905.           if (dlinit() == -1)
  906.             return 0;
  907.         
  908.           if (nswghba)
  909.             return nswghba(addr, len, type);
  910.           else
  911.             return nss_ghba(addr,
  912.                             len, type, &hp, buf, sizeof(buf), &h_errno);
  913.         }
  914.  
  915.  
  916. -----------------------------------------------------------
  917.  
  918. 4) TOPIC: BSD/Solaris 1/POSIX Signal Primer
  919.  
  920. [Last modified: 20 September 93]
  921.  
  922.  
  923. The most common problem encountered when porting BSD/Solaris 1
  924. signal code is that Solaris 2 (and SVR4) handles interrupted
  925. systems calls differently than does BSD. In Solaris 2 (SVR4),
  926. system calls are interrupted and return EINTR, unless the call is
  927. read, write, or some other call that returns the number of bytes
  928. read/written (unless 0 bytes have been read/written, in which
  929. case the call returns EINTR). 
  930.  
  931. On the other hand, system calls are restarted on BSD/Solaris 1
  932. systems. The signal calls can be made to restart by specifying a
  933. SA_RESTART with sigaction().  Note, however, that code that
  934. relies on restartable system calls is generally considered bad
  935. practice. The following code is provided for illustrative
  936. purposes only. It is recommended that you remove these
  937. dependencies. Sigaction is the preferred (POSIX) way of
  938. installing signal handlers.  
  939.  
  940.  
  941.         The BSD/Solaris 1 code 
  942.  
  943.                 omask = sigblock(sigmask(SIGXXX));
  944.                 do_stuff_while_SIGXXX_blocked();
  945.                 (void)sigsetmask(omask);
  946.         
  947.         can be emulated by
  948.  
  949.                 sigset_t block, oblock;
  950.                 struct   sigaction act, oact;
  951.                 ....
  952.                 (void)sigemptyset(&block);
  953.                 (void)sigaddset(&block, SIGXXX);
  954.                 if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
  955.                         perror("sigprocmask");
  956.                 do_stuff_while_SIGXXX_blocked();
  957.                 (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
  958.         #ifdef  SA_RESTART                      /* make restartable */
  959.                 act.sa_flags = SA_RESTART;
  960.         #endif  /* SA_RESTART */
  961.                 if (sigaction(SIGXXX, &act, &oact) < 0)
  962.                        return(SIG_ERR);
  963.  
  964.  
  965.         Note that this (emulating) construct is also available on
  966.         Solaris 1 (sans SA_RESTART), so should work on either
  967.         Solaris 1 or SVR4.
  968.  
  969.         Another possibility would be to emulate BSD signal(2)
  970.         semantics as follows:
  971.  
  972.         Sigfunc *bsdsignal(int signo, Sigfunc *alarm_catcher)
  973.         {
  974.  
  975.          struct sigaction act;
  976.          act.sa_handler = alarm_catcher;
  977.          sigemptyset(&act.sa_mask);
  978.          act.sa_flags = SA_RESTART;
  979.          if(sigaction(signo, &act,NULL) == -1) {
  980.            perror("signal:");
  981.            return(SIG_ERR);
  982.         }
  983.  
  984. Another problem revolves around the use of setjmp and longjmp.
  985. With 4.3+BSD  the setjmp and longjmp save and restore the signal
  986. mask. The default behavior for SVR4 is not to save and restore
  987. the signal mask. Note that these calls are MT-Unsafe.
  988.  
  989. The POSIX.1 interface allows you to do either, by using a second
  990. argument, savemask, for sigsetjmp. To cause the signal mask to be
  991. saved and restored (emulating setjmp/longjmp behavior), use a
  992. nonzero savemask.  For example,
  993.  
  994.  
  995.                 #include        <stdio.h>
  996.                 #include        <stdlib.h>
  997.                 #include        <setjmp.h>
  998.                 
  999.                 sigjmp_buf      env;
  1000.                 int             savemask;
  1001.                 
  1002.                 ....
  1003.                 
  1004.                 savemask = 1;
  1005.                 #ifdef  HAS_SIGSETJMP
  1006.                         sigsetjmp(env, savemask);
  1007.                 #endif  HAS_SIGSETJMP
  1008.  
  1009.                 ...
  1010.  
  1011. In this case, the sigsetjmp saves the current signal mask of the
  1012. process in the saved environment (sigjmp_buf). Now, if the
  1013. environment was saved by a call to sigsetjmp with a nonzero
  1014. savemask, then a subsequent siglongjmp call will restore the
  1015. saved signal mask.    
  1016.  
  1017.  
  1018. To summarize,  some basic rules are:
  1019.  
  1020.         (i).    Limit signal handling code to the POSIX interface
  1021.                 whenever possible. 
  1022.  
  1023.         (ii).   Use sigaction to install signal handlers whenever
  1024.                 possible. Use Standard C's signal() only for
  1025.                 portability to non-POSIX systems. 
  1026.  
  1027.         (iii).  Avoid code that relies on restartable system calls. 
  1028.  
  1029.         (iv).   The main difference between SVR4 sigset() (not
  1030.                 POSIX) and SunOS 4.x/BSD signal() is that system
  1031.                 calls will return EINTR with sigset() but will be
  1032.                 restarted on BSD/SunOS 4.x. On SVR4 EINTR is only
  1033.                 returned when no bytes have been read/written.     
  1034.  
  1035.  
  1036. -----------------------------------------------------------------------------
  1037.  
  1038. 5) TOPIC: Waiting for Children to Exit
  1039.  
  1040. [Last modified: 26 October 93]
  1041.  
  1042.  
  1043. waitpid(2) is the preferred (POSIX) interface. Wait3 can be
  1044. replaced by waitpid (when you don't need the rusage). For
  1045. example, the BSD segment  
  1046.         
  1047.         while((id = wait(&stat)) >=0 && id != pid);
  1048.  
  1049. can be approximated using the POSIX waidpid(2) interface by code
  1050. of the form: 
  1051.  
  1052.         int status;
  1053.         int options;                    /* e.g., WNOHANG */
  1054.         ....
  1055.         options = WNOHANG;
  1056.         if (waitpid((pid_t) -1, &status, options) == -1)
  1057.                 perror("waitpid");
  1058.         }
  1059.  
  1060.  
  1061. Note here that if you execute a signal(SIGCHLD, SIG_IGN) or
  1062. sigset(SIGCHLD, SIG_IGN), Solaris will discard all child exit
  1063. statuses and reap the child processes without giving the parent a
  1064. chance to wait. That is, waitpid(2) will return -1 with an ECHILD. 
  1065.  
  1066.  
  1067. Another possibility is emulate the BSD wait(2) call with SVR4's
  1068. waitid(2). The code fragment below is an example. In this case,
  1069. we wait for a particular child in our process group ((pid_t) 0)
  1070. to exit (WEXITED).
  1071.  
  1072.  
  1073.         #ifdef  SVR4
  1074.         #include <sys/types.h>
  1075.         #include <sys/wait.h>
  1076.                 siginfo_t       stat;
  1077.                 int             retcode;
  1078.         #else
  1079.                 union   wait    stat;
  1080.         #endif
  1081.  
  1082.         .....
  1083.  
  1084.         #ifdef  SVR4
  1085.               while (retcode = waitid(P_ALL,(pid_t) 0, &stat, WEXITED)) {
  1086.                 if (retcode < 0) {
  1087.                   perror("waitid");
  1088.                   exit(1);
  1089.                 }
  1090.                 if (stat.si_pid == pid)
  1091.                   break;
  1092.               }
  1093.         #else           /* BSD */
  1094.                while((id = wait(&stat)) >=0 && id != pid);
  1095.         #endif  /* SVR4 */
  1096.  
  1097.  
  1098.  
  1099. -----------------------------------------------------------------------------
  1100.  
  1101. 6) TOPIC: Dealing With Shadow Password Files
  1102.  
  1103. [Last modified: 19 August 93]
  1104.  
  1105. The following code segment outlines how to handle shadow password
  1106. files. In the outline below, <passwd> is the clear text password.
  1107. Note that shadow passwords are part of SVR4, so again we have the
  1108. conflict between using high level system definitions (e.g., SVR4)
  1109. and feature definitions (for systems other than SVR4). I'll use
  1110. feature a feature definition (HAVE_SHADOW_H) to illustrate this.
  1111.  
  1112.  
  1113.         #ifdef  HAVE_SHADOW_H
  1114.         #include <shadow.h>
  1115.             register struct spwd    *sp;
  1116.         #endif  /* HAVE_SHADOW_H */
  1117.  
  1118.              .....
  1119.                 
  1120.         #ifdef  HAVE_SHADOW_H
  1121.             if ((sp = getspnam(<username>)) == NULL)
  1122.                <no password entry for username>
  1123.             if (sp->sp_pwdp == NULL)
  1124.                <NULL password for username>
  1125.             if (strcmp (crypt (<passwd>, sp->sp_pwdp), sp->sp_pwdp) != 0)
  1126.         #else 
  1127.             if ((pw = getpwnam(<username>)) == NULL)
  1128.                <no password entry for username>
  1129.             if (pw->pw_passwd == NULL)
  1130.                <NULL password for username>
  1131.             if (strcmp (crypt (<passwd>, pw->pw_passwd), pw->pw_passwd) != 0)
  1132.         #endif  /* HAVE_SHADOW_H */
  1133.                <incorrect password for username>
  1134.                        
  1135.  
  1136. -----------------------------------------------------------------------------
  1137.  
  1138. 7)* TOPIC: Some Compatabilty Problems
  1139.  
  1140. [Last modified: 02 September 93]
  1141.  
  1142.         (i).     vfork doesn't work in Solaris 2
  1143.  
  1144.                 [Editor's Note: The following observation and
  1145.                 example comes courtesy of Paul Eggert
  1146.                 (eggert@twinsun.com). DM] 
  1147.  
  1148.                 In Solaris 2, if a vfork'ed child adjusts signal
  1149.                 handling before exec'ing, signal handling is munged in
  1150.                 the parent in ways that lead to unreliable results;
  1151.                 the parent can dump core in some cases.  This bug
  1152.                 affects some widely distributed programs, so when
  1153.                 building a program that adjusts signal handlers
  1154.                 between `vfork' and `exec', be careful to override its
  1155.                 configuration to use `fork' instead. 
  1156.  
  1157.                 Sun doesn't consider this behavior to be a bug,
  1158.                 so it's not likely to be fixed. 
  1159.  
  1160.                 Here's an illustration of the bug.  This program
  1161.                 works fine in SunOS 4.1.x, but dumps core in
  1162.                 Solaris 2.x. 
  1163.  
  1164.                         #include <signal.h>
  1165.                         #include <unistd.h>
  1166.  
  1167.                         #ifdef SIGLOST          /* must be SunOS 4.1.x */
  1168.                         #include <vfork.h>
  1169.                         #endif
  1170.  
  1171.                         int signalled;
  1172.  
  1173.                         void catch (sig)
  1174.                              int sig;
  1175.                         {
  1176.                              signalled = 1;
  1177.                         }
  1178.  
  1179.                         int main()
  1180.                         {
  1181.                              signal (SIGINT, catch);
  1182.                              if (vfork () == 0) {               /* child */
  1183.                                  signal (SIGINT, SIG_IGN);
  1184.                                  execlp ("sleep", "sleep", "10", (char *) 0);
  1185.                              }
  1186.         
  1187.                             /* parent here */
  1188.  
  1189.                              kill (getpid (), SIGINT);
  1190.                              return signalled != 1;
  1191.                         }
  1192.  
  1193.  
  1194.         (ii).   chown(2) does not allow uid/gid values greater
  1195.                 than 60002 on Solaris 2.[0-3]. Check /usr/include/limits.h, 
  1196.                 which contains:
  1197.  
  1198.                 #define UID_MAX         60002   
  1199.  
  1200.  
  1201. -----------------------------------------------------------------------------
  1202.  
  1203. 8)* TOPIC: Other Resources
  1204.  
  1205. [Last modified: 27 September 93]
  1206.  
  1207. Porting to Solaris 2
  1208. --------------------
  1209.  
  1210. A excellent text on this subject is  "Solaris Porting Guide",
  1211. SunSoft ISV Engineering, et. al., Prentice Hall, 1993. ISBN
  1212. 0-13-030396-8. 
  1213.  
  1214. Solaris 2 General FAQ
  1215. ---------------------
  1216.  
  1217. The official Solaris 2 Frequently Answered Questions is
  1218. maintained by Ian Darwin, ian@sq.com, and is posted once or twice 
  1219. a month to various newsgroups including comp.unix.solaris and
  1220. comp.answers.
  1221.  
  1222. General
  1223. -------
  1224.  
  1225. "Internetworking with TCP/IP: Volume III Client-Server Programming
  1226. & Applications (AT&T TLI Edition)", Douglas E. Comer & David L.
  1227. Stevens, Prentice-Hall. ISBN 0-13-474230-3. Nice reference for
  1228. TLI programming, etc.
  1229.  
  1230. "Networking Applications on UNIX System V", Mike Padovano, ISBN
  1231. 013-613555. A good reference for System V.
  1232.  
  1233. "UNIX, POSIX, and Open Systems: The Open Standards Puzzle", John
  1234. S. Quarterman and Susanne Wilhelm, Addison-Wesley, 1993. ISBN
  1235. 0-201-52772-3. Another nice modern reference.
  1236.  
  1237. "UNIX System V Network Programming", Steve Rago, ISBN
  1238. 0-201-56318-5. Another good System V reference.
  1239.  
  1240. "Advanced Programming in the UNIX Environment", W. Richard
  1241. Stevens, Addison Wesley, 1992, ISBN 0-201-56317-1, is a nice, in
  1242. depth text covering large parts of this topic.
  1243.  
  1244. ANSI C
  1245. ------
  1246.  
  1247. A very nice text here is "The Standard C Library", P.J. Plauger,
  1248. Prentice Hall, 1992, ISBN 0-13-131509-9.
  1249.  
  1250. Another example of the many texts here is "C,  a Reference
  1251. Manual", Harbison and Steele, Prentice Hall. ISBN 0-13-110933-2.  
  1252.  
  1253. POSIX
  1254. -----
  1255.  
  1256. A nice reference text on the POSIX interface is "POSIX
  1257. Programmer's Guide", Donald Levine, O'Reily & Associates, 1991.
  1258. ISBN 0-937175-73-0. 
  1259.  
  1260.  
  1261. ACKNOWLEDGMENTS
  1262.  
  1263. I would like to thank everyone who contributed to this, and I
  1264. hope that it clarifies some of these issues. I would especially 
  1265. acknowledge the contributions of Casper H.S. Dik and J.G. Vons in
  1266. helping me organize my thoughts on all this.
  1267.  
  1268. Thanks to:
  1269.  
  1270.         Jamshid Afshar          <jamshid@ses.com>
  1271.         Pedro Acebes Bayon      <pacebes@tid.es>
  1272.         Ian Darwin              <ian@sq.com>
  1273.         Casper H.S. Dik         <casper@fwi.uva.nl>
  1274.         Paul Eggert             <eggert@twinsun.com>
  1275.         Stephen L Favor         <xcpslf@atom.oryx.com>
  1276.         Charles Francois        <cbf@gotham.east.sun.com>
  1277.         Pete Hartman            <pwh@bradley.bradley.edu>
  1278.         Guy Harris              <guy@auspex.com>
  1279.         Jens-Uwe Mager          <jum@anubis.han.de>
  1280.         Thomas Maslen           <maslen@eng.sun.com>
  1281.         Richard M. Mathews      <richard@astro.west.sun.com>
  1282.         Davin Milun             <milun@cs.buffalo.edu>
  1283.         Paul Pomes              <Paul-Pomes@uiuc.edu>
  1284.         Andrew Roach            <andrewr@ultrix.sun.com>
  1285.         M C Srivas              <M._C._Srivas@transarc.com>
  1286.         Larry W. Virden         <lwv26@cas.org>
  1287.         J.G. Vons               <vons%ulysse@crbca1.sinet.slb.com>
  1288.         Peter Wemm              <peter@DIALix.oz.au>
  1289.         christos@deshaw.com
  1290.         jorgens@pvv.unit.no
  1291.         Malte            <malte@techfak.uni-bielefeld.de>
  1292.  
  1293. ----- End of Solaris 2 Porting FAQ -- Maintained by David Meyer meyer@ns.uoregon.edu --
  1294.  
  1295.  
  1296.  
  1297.         David M. Meyer 503/346-1747
  1298.         meyer@cambium.uoregon.edu
  1299.         Fri Jul 16 14:59:28 1993
  1300.  
  1301.         $Header: /net/network-services/disk1/home/meyer/FAQ/RCS/porting-FAQ,v 1.56 1994/04/25 12:34:52 meyer Exp $
  1302.  
  1303.  
  1304.  
  1305.